package com.acme.bankapp.service.bank.builder;

import java.util.Map;

import com.acme.bankapp.domain.bank.Account;
import com.acme.bankapp.domain.bank.CheckingAccount;
import com.acme.bankapp.domain.bank.SavingAccount;

/**
 * Builds account from properties map.
 * 
 */
public class AccountBuilder extends AbstractBuilder<Account> {
	private static final String ACCOUNT_TYPE_FIELD = "accounttype";
	private static final String BALANCE_FIELD = "balance";
	private static final String OVERDRAFT_FIELD = "overdraft";

	AccountType accountType = null;
	Double balance = null;
	Double overdraft = null;

	private void setAccountType(String accountType)
			throws BuildingFailedException {
		validateNotNull(accountType);
		switch (accountType) {
		case "c":
			this.accountType = AccountType.CHECKING_ACCOUNT;
			break;
		case "s":
			this.accountType = AccountType.SAVING_ACCOUNT;
			break;
		default:
			throw new BuildingFailedException();
		}
	}

	private void setBalance(String balance) throws BuildingFailedException {
		validateNotNull(balance);
		this.balance = parseDouble(balance);
	}

	private void setOverdraft(String overdraft) throws BuildingFailedException {
		if (overdraft != null) {
			this.overdraft = parseDouble(overdraft);
		}
	}

	private Account build() throws BuildingFailedException {
		switch (accountType) {
		case CHECKING_ACCOUNT:
			validateNotNull(overdraft);
			return new CheckingAccount(balance, overdraft);
		case SAVING_ACCOUNT:
			return new SavingAccount(balance);
		}
		throw new BuildingFailedException();
	}

	/**
	 * Builds new account from properties or throws exception on failure.
	 * 
	 * @param properties
	 *            map of properties
	 * @return newly created account
	 * @throws BuildingFailedException
	 */
	@Override
	public Account buildFromProperties(Map<String, String> properties)
			throws BuildingFailedException {
		setAccountType(properties.get(ACCOUNT_TYPE_FIELD));
		setBalance(properties.get(BALANCE_FIELD));
		setOverdraft(properties.get(OVERDRAFT_FIELD));
		return build();
	}
}

enum AccountType {
	CHECKING_ACCOUNT, SAVING_ACCOUNT
}